/*
 * Reksio - Memory Map Editor
 * Copyright (C) 2023 CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In applying this licence, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an Intergovernmental Organization or
 * submit itself to any jurisdiction.
 */

#include "searchwindow.h"
#include "ui_searchwindow.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "nodesmodel.h"
#include "attributesmodel.h"
#include "customnodesview.h"
#include "customattributesview.h"
#include "utils.h"
#include <QRegularExpression>
#include <QMessageBox>
SearchWindow::SearchWindow(MainWindow* main_window) :
    QWidget(main_window),
    ui(new Ui::SearchWindow),
    main_window(main_window),
    using_regex(false)
{
    ui->setupUi(this);
    setWindowFlag(Qt::Window);
    setAttribute(Qt::WA_DeleteOnClose, false);

    ui->resultsTableWidget->resizeRowsToContents();
    ui->resultsTableWidget->resizeColumnsToContents();
}

SearchWindow::~SearchWindow()
{
    delete ui;
}

void SearchWindow::on_searchButton_clicked()
{       
    const QString& search_text = ui->searchField->text();

    Qt::CaseSensitivity case_sensitivity = ui->caseSensitiveCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;

    QRegularExpression regex(search_text);
    const bool regex_valid = regex.isValid();
    if(regex_valid)
    {
        regex.optimize();
    }
    else
    {
        QMessageBox::warning(this, "Regular expression is not valid", "Your regular expression is not valid!\n" + regex.errorString());
        return;
    }

    ui->resultsTableWidget->setRowCount(0);
    NodesModel* nodes_model = main_window->getNodesModel();
    QModelIndexList index_list;
    nodes_model->getAllChildren(main_window->nodesView->rootIndex(), index_list);

    for(const auto& index: index_list)
    {
        MemoryNode* node = nodes_model->getItem(index);
        for(const auto& attr: node->getAttributeContainer()->getAllAttributes())
        {
            bool found = false;
            const QString& subject = QString::fromStdString(attr->getValue());
            if(using_regex)
            {
                const QRegularExpressionMatch& match = regex.match(subject);
                found = match.hasMatch();
            }
            else
            {
                found = subject.contains(search_text, case_sensitivity);
            }
            if(found)
            {
                const int row = ui->resultsTableWidget->rowCount();
                ui->resultsTableWidget->insertRow(row);
                QTableWidgetItem* node_type_item = new QTableWidgetItem(QString::fromStdString(node->getType()));
                QTableWidgetItem* node_name_item = new QTableWidgetItem(QString::fromStdString(join(node->nodeLocation(), "/")));
                QTableWidgetItem* attribute_name_item = new QTableWidgetItem(QString::fromStdString(join(attr->getFullName(), "/")));
                ui->resultsTableWidget->setItem(row, 0, node_type_item); // takes ownership
                ui->resultsTableWidget->setItem(row, 1, node_name_item); // takes ownership
                ui->resultsTableWidget->setItem(row, 2, attribute_name_item); // takes ownership
                setData(node_type_item, node, attr);
                setData(node_name_item, node, attr);
                setData(attribute_name_item, node, attr);
            }
        }
    }
    ui->resultsTableWidget->resizeRowsToContents();
    ui->resultsTableWidget->resizeColumnsToContents();
}

void SearchWindow::on_searchField_returnPressed()
{
    on_searchButton_clicked();
}

void SearchWindow::on_resultsTableWidget_itemClicked(QTableWidgetItem *item)
{
    MemoryNode* node = item->data(MemoryNodePtr).value<MemoryNode*>();
    Attribute* attr = item->data(AttributePtr).value<Attribute*>();
    const QModelIndex& node_index = main_window->getNodesModel()->getIndex(node);
    if(node_index.isValid())
    {
        main_window->nodesView->selectionModel()->select(node_index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
        main_window->nodesView->scrollTo(node_index);
        main_window->nodesViewCurrentChanged(node_index);

        AttributesModel* attrib_model = main_window->getCurrentAttributesModel();
        const QModelIndex& attrib_index = attrib_model->getIndex(attr);
        if(attrib_index.isValid())
        {
            main_window->attributesView->scrollTo(attrib_index);
            main_window->attributesView->selectionModel()->select(attrib_index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
        }
    }
}

void SearchWindow::setData(QTableWidgetItem *item, MemoryNode *node, Attribute *attr)
{
    item->setData(MemoryNodePtr, QVariant::fromValue(node));
    item->setData(AttributePtr, QVariant::fromValue(attr));
}

void SearchWindow::on_regularExpressionCheckBox_stateChanged(int arg1)
{
    if(arg1 == Qt::Unchecked)
    {
        using_regex = false;
    }
    else if (arg1 == Qt::Checked)
    {
        using_regex = true;
    }
}
